package io.renren.modules.iots.utils.comment;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;

import com.alibaba.fastjson.JSON;

import io.renren.modules.iots.entity.CollectionAgentConfig;
import io.renren.modules.iots.entity.IOTPBean;
import io.renren.modules.iots.entity.IOTPBody;
import io.renren.modules.iots.entity.IotsIoserverInfoEntity;
import io.renren.modules.iots.utils.config.IotsConfig;
import io.renren.modules.iots.utils.socket.client.SingleSocketWriteThread;
import io.renren.modules.iots.utils.socket.client.SocketBean;
import io.renren.modules.iots.utils.socket.client.SocketUtils;
import io.renren.modules.iots.utils.socket.server.NIOSServerForControl;
import io.renren.modules.iots.utils.socket.server.NIOSServerForWeb;

/**
 * @ClassName: HandleOfIotpbeanType
 * @Description:	不同IOTP协议类型的处理类
 * 	0 缺省值
 *	1 采集数据消息
 *	2 采集数据消息返回值
 *	3 控制消息
 *	4 控制消息返回值
 *	5 采集代理配置消息
 *	6 采集代理配置消息返回值
 *	7 状态消息
 *	8 状态消息返回值
 *	9 查询配置信息
 *	10 配置返回信息
 *	11 获取设备列表信息
 *	12 获取设备列表返回值
 *	13 获取变量列表信息
 *	14 获取变量列表信息返回值
 *	15 物联网接口配置信息
 *	16 物联网接口配置消息返回值
 * @author 周西栋
 * @date 2018年6月14日
 *
 */
public class HandleOfIotpbeanType {
	
	/**
	 * 日志
	 */
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
    private KafkaTemplate kafkaTemplate;
	@Autowired
	private ResolveDomain resolveDomain;
	
	/**
	 * 获得用于Web端的单例
	 */
	private NIOSServerForWeb serverForWeb = NIOSServerForWeb.getInstance();
	
	/**
	 * 获得用于控制接口服务的单例
	 */
	private NIOSServerForControl serverForControl = NIOSServerForControl.getInstance();
	
	/**
	 * 采集数据的topic信息
	 */
	private String sendMsgTopic = null;
	
	/**
	 * 采集设备状态的topic信息
	 */
	private String sendDeviceStatusMsgTopic = null;
	
	/**
	 * 采集服务状态的topic信息
	 */
	private String sendServerStatusMsgTopic = null;
	
	/**
	 * @author 周西栋
	 * @date 2018年6月14日
	 * @Title: type1
	 * @Description: 采集数据消息（采集代理向物联网接口服务发送消息）
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type1(IOTPBean iotp){
		// 获得kafka的生产者，将iotp放进指定的topic中
		try {
			kafkaTemplate.send(sendMsgTopic ,"data_key", JSON.toJSONString(iotp));
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月19日
	 * @Title: type3
	 * @Description: 控制消息
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type3(IOTPBean iotp){
		// 获取消息体
		IOTPBody ib = iotp.getBody();
		List<String> list = ib.getBodyList();
		// 需要发送的命令
		Map<IotsIoserverInfoEntity,List<String>> map = new HashMap<>();
		// IP是否存在的标记
		boolean ipIsNotOk = true;
		// 存放不正确的IOServer的集合
		List<String> ipIsNotOk_list = new ArrayList<>();
		// ioserver_id
		String ioserver_id = null;
		// 获取控制命令信息
		for(String str : list){// str的正确格式为  http://域名/IOServer标识/分组标识/设备标识/变量标识/写变量值_时间戳_超时时间_尝试次数
			ipIsNotOk = true;
			// 解析出IOServer的标示（id）
			if(str.split("://").length == 2 && str.split("://")[1].split("/").length == 6){
				ioserver_id = str.split("://")[1].split("/")[1];
				// 当IotsIoserverInfoEntity数量少时（大于200时），该处应用关键字contains做比较；***
				IotsIoserverInfoEntity iii = checkIOServerID(ioserver_id);
				if(iii != null){
					// 将控制命令按IOServer分类
					map = getSendControlMap(map,iii,str);
					ipIsNotOk = false;
				}
				if(ipIsNotOk){
					ipIsNotOk_list.add(ioserver_id);
				}
			}
		}
		// 将不正确的IOServer标示打印到日志中
		logger.error("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
		logger.error("控制接口服务发过来的控制命令中不正确的IOServer标示有：");
		logger.error(ipIsNotOk_list.toString());
		logger.error("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
		try {
			// 将分好类的控制消息 分发给IOServer
			sendControlMessgae(map,iotp);// 注意：iotp是socketClient端发送过来的iotp，即控制接口发过来的iotp
			// 将不用的对象置空，加速内存回收
			list = null;
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月28日
	 * @version V1.0
	 * @Title: type4
	 * @Description: 将控制信息端返回值发送给控制接口服务
	 * @param @param iotp    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type4(IOTPBean iotp) {
		return serverForControl.send_Msg(iotp);
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: type5
	 * @Description: 采集代理配置消息
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type5(IOTPBean iotp){
		// 获取BodyList中的信息
		List<String> msgs = iotp.getBody().getBodyList();
		// 存放不正确的IOServer的集合
		List<String> ipIsNotOk_list = new ArrayList<>();
		for(String cacStr : msgs){
			// 获得配置中的IOServerid
			CollectionAgentConfig cac = JSON.parseObject(cacStr, CollectionAgentConfig.class);
			// 获取IOServer的ID
			String ioserver_id = cac.getIOServer_id();
			// 检查ioserver_id是不是在配置信息中存在
			IotsIoserverInfoEntity iii = checkIOServerID(ioserver_id);
			if(iii != null){// 存在时
				// 拿到写线程
				SingleSocketWriteThread write = SingleSocketWriteThread.getInstance();
				// 根据iotsIoserverInfoEntity拿到SocketBean
				SocketBean sb = SocketUtils.SOCKETBEAN_MAP.get(iii.getIpAddress());// 因为方法type3已经验证过了，所以这里一定会拿到对象
				// 将采集代理配置信息发送给IOServer
				IOTPBean iotp_send = getIOTPBeanOfCollectionAhentConfig(iotp,JSON.toJSONString(cac));
				write.send_single(sb, iotp_send);
			} else {// 不存在时
				ipIsNotOk_list.add(ioserver_id);
			}
		}
		// 将不正确的IOServer标示打印到日志中
		logger.error("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
		logger.error("控制接口服务发过来的控制命令中不正确的IOServer标示有：");
		logger.error(ipIsNotOk_list.toString());
		logger.error("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
		return false;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月28日
	 * @version V1.0
	 * @Title: type6
	 * @Description: 将配置采集代理的配置信息返回值发给Web端
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type6(IOTPBean iotp) {
		return serverForWeb.send_Msg(iotp);
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: type7
	 * @Description: 状态消息
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type7(IOTPBean iotp){
		// 获得kafka的生产者，将iotp放进指定的topic中
		try {
			if(iotp.getBody().getSubtype() == 0){// 服务状态
				kafkaTemplate.send(sendServerStatusMsgTopic ,"server_status_key", JSON.toJSONString(iotp));
				return true;
			}else if(iotp.getBody().getSubtype() == 1){// 设备状态
				kafkaTemplate.send(sendDeviceStatusMsgTopic ,"device_status_key", JSON.toJSONString(iotp));
				return true;
			}else{// 无效数据
				return false;
			}
		} catch (Exception e) {
			return false;
		}
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月25日
	 * @Title: type11
	 * @Description: 获取设备列表信息（暂时不用，现在是分步同步设备和变量，改成了同时同步设备和变量。）
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type11(IOTPBean iotp){
		// 获取消息体信息
		IOTPBody body = iotp.getBody();
		// 获取配置信息
		List<String> configStr = body.getBodyList();
		CollectionAgentConfig cac = null;
		// IP是否存在的标记
		boolean ipIsNotOk = true;
		// 存放不正确的IOServer的集合
		List<String> ipIsNotOk_list = new ArrayList<>();
		for(String cof: configStr){
			try {
				cac = JSON.parseObject(cof, CollectionAgentConfig.class);
			} catch (Exception e) {
				logger.error("配置信息转换错误，错误的配置信息为："+cof);
				continue;
			}
			// 检查ioserver_id是不是在配置信息中存在
			IotsIoserverInfoEntity iii = checkIOServerID(cac.getIOServer_id());
			if(iii != null){// 存在时
				// 拿到写线程
				SingleSocketWriteThread write = SingleSocketWriteThread.getInstance();
				// 根据iotsIoserverInfoEntity拿到SocketBean
				SocketBean sb = SocketUtils.SOCKETBEAN_MAP.get(iii.getIpAddress());// 因为方法type3已经验证过了，所以这里一定会拿到对象
				// 将采集代理配置信息发送给IOServer
				IOTPBean iotp_send = getIOTPBeanOfCollectionAhentConfig(iotp,JSON.toJSONString(cac));
				write.send_single(sb, iotp_send);
			} else {// 不存在时
				ipIsNotOk_list.add(cac.getIOServer_id());
			}
		}
		return false;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月28日
	 * @version V1.0
	 * @Title: type12
	 * @Description: 将收到的设备列表信息发送给Web端
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type12(IOTPBean iotp){
		return serverForWeb.send_Msg(iotp);
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月28日
	 * @version V1.0
	 * @Title: type13
	 * @Description: 获取变量列表信息（暂时不用，现在是分步同步设备和变量，改成了同时同步设备和变量。）
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type13(IOTPBean iotp){
		// 获取消息体信息
		IOTPBody body = iotp.getBody();
		// 获取配置信息
		List<String> configStr = body.getBodyList();
		CollectionAgentConfig cac = null;
		// IP是否存在的标记
		boolean ipIsNotOk = true;
		// 存放不正确的IOServer的集合
		List<String> ipIsNotOk_list = new ArrayList<>();
		for(String cof: configStr){
			try {
				cac = JSON.parseObject(cof, CollectionAgentConfig.class);
			} catch (Exception e) {
				logger.error("配置信息转换错误，错误的配置信息为："+cof);
				continue;
			}
			// 检查ioserver_id是不是在配置信息中存在
			IotsIoserverInfoEntity iii = checkIOServerID(cac.getIOServer_id());
			if(iii != null){// 存在时
				// 拿到写线程
				SingleSocketWriteThread write = SingleSocketWriteThread.getInstance();
				// 根据iotsIoserverInfoEntity拿到SocketBean
				SocketBean sb = SocketUtils.SOCKETBEAN_MAP.get(iii.getIpAddress());// 因为方法type3已经验证过了，所以这里一定会拿到对象
				// 将采集代理配置信息发送给IOServer
				IOTPBean iotp_send = getIOTPBeanOfCollectionAhentConfig(iotp,JSON.toJSONString(cac));
				write.send_single(sb, iotp_send);
			} else {// 不存在时
				ipIsNotOk_list.add(cac.getIOServer_id());
			}
		}
		return false;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月28日
	 * @version V1.0
	 * @Title: type14
	 * @Description: 将返回的变量列表信息返回给Web端
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type14(IOTPBean iotp){
		return serverForWeb.send_Msg(iotp);
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月28日
	 * @version V1.0
	 * @Title: type15
	 * @Description: 物联网接口的配置信息
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type15(IOTPBean iotp){
		// 拿到系统端配置信息
		IotsConfig config = IotsConfig.getInstance();
		// 从协议体中获得配置信息
		String configStr = iotp.getBody().getBodyList().get(0);
		if(configStr == null || "".equals(configStr)) {
			return false;
		}
		List<IotsIoserverInfoEntity> array = JSON.parseArray(configStr, IotsIoserverInfoEntity.class);
		if(array == null) {
			return false;
		}else {
			config.setIpAndPortList(array);
			return true;
		}
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月28日
	 * @version V1.0
	 * @Title: type21
	 * @Description: 同时获取设备和变量信息
	 * @param @param iotp
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	public boolean type21(IOTPBean iotp) {
		// 因为采集代理那边已经写完了这个类型，约定的是11，故此处更改为11
		iotp.setType(11);
		// 获取消息体信息
		IOTPBody body = iotp.getBody();
		// 获取配置信息
		List<String> configStr = body.getBodyList();
		CollectionAgentConfig cac = null;
		// IP是否存在的标记
		boolean ipIsNotOk = true;
		// 存放不正确的IOServer的集合
		List<String> ipIsNotOk_list = new ArrayList<>();
		for(String cof: configStr){
			try {
				cac = JSON.parseObject(cof, CollectionAgentConfig.class);
			} catch (Exception e) {
				logger.error("配置信息转换错误，错误的配置信息为："+cof);
				continue;
			}
			// 检查ioserver_id是不是在配置信息中存在
			IotsIoserverInfoEntity iii = checkIOServerID(cac.getIOServer_id());
			if(iii != null){// 存在时
				// 拿到写线程
				SingleSocketWriteThread write = SingleSocketWriteThread.getInstance();
				// 根据iotsIoserverInfoEntity拿到SocketBean
				SocketBean sb = SocketUtils.SOCKETBEAN_MAP.get(iii.getIpAddress());// 因为方法type3已经验证过了，所以这里一定会拿到对象
				// 将采集代理配置信息发送给IOServer
				IOTPBean iotp_send = getIOTPBeanOfCollectionAhentConfig(iotp,JSON.toJSONString(cac));
				write.send_single(sb, iotp_send);
			} else {// 不存在时
				ipIsNotOk_list.add(cac.getIOServer_id());
			}
		}
		return false;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: getSendControlMap
	 * @Description: 将控制消息分类
	 * @param @param map
	 * @param @param iotsIoserverInfoEntity
	 * @param @param controlMsg
	 * @param @return    参数
	 * @return Map<IotsIoserverInfoEntity,List<String>>    返回类型
	 * @throws
	 */
	private Map<IotsIoserverInfoEntity,List<String>> getSendControlMap(Map<IotsIoserverInfoEntity,List<String>> map,IotsIoserverInfoEntity iotsIoserverInfoEntity,String controlMsg){
		List<String> list = map.get(iotsIoserverInfoEntity) != null ? map.get(iotsIoserverInfoEntity) : new ArrayList<>();
		list.add(controlMsg);
		map.put(iotsIoserverInfoEntity, list);
		return map;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: sendControlMessgae
	 * @Description: 将控制命令发送给相应的IOServer
	 * @param @param map    参数
	 * @return void    返回类型
	 * @throws
	 */
	private void sendControlMessgae(Map<IotsIoserverInfoEntity,List<String>> map,IOTPBean iotp){
		// 拿到写线程
		SingleSocketWriteThread write = SingleSocketWriteThread.getInstance();
		for(IotsIoserverInfoEntity iotsIoserverInfoEntity : map.keySet()){
			// 根据iotsIoserverInfoEntity拿到SocketBean
			SocketBean sb = SocketUtils.SOCKETBEAN_MAP.get(iotsIoserverInfoEntity.getIpAddress());// 因为方法type3已经验证过了，所以这里一定会拿到对象
			// 将控制命令发送给IOServer
			IOTPBean iotp_send = getIOTPBeanOfControl(iotp,map.get(iotsIoserverInfoEntity));
			write.send_single(sb, iotp_send);
		}
		
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: getIOTPBeanOfControl
	 * @Description: 封装协议对象--控制命令
	 * @param @param iotp
	 * @param @param list
	 * @param @return    参数
	 * @return IOTPBean    返回类型
	 * @throws
	 */
	private IOTPBean getIOTPBeanOfControl(IOTPBean iotp,List<String> list){
		IOTPBean iotpbean = copyIOTPBean(iotp);
		iotpbean.getBody().setBodyList(list);
		return iotpbean;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: getIOTPBeanOfCollectionAhentConfig
	 * @Description: 封装协议对象--采集代理配置信息
	 * @param @param iotp
	 * @param @param configStr
	 * @param @return    参数
	 * @return IOTPBean    返回类型
	 * @throws
	 */
	private IOTPBean getIOTPBeanOfCollectionAhentConfig(IOTPBean iotp,String configStr){
		IOTPBean iotpbean = copyIOTPBean(iotp);
		iotpbean.getBody().getBodyList().add(configStr);
		return iotpbean;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: copyIOTPBean
	 * @Description: 复制IOTPBean
	 * @param @param iotp
	 * @param @return    参数
	 * @return IOTPBean    返回类型
	 * @throws
	 */
	private IOTPBean copyIOTPBean(IOTPBean iotp){
		IOTPBean iotpbean = new IOTPBean();
		iotpbean.setTag(iotp.getTag()); // 协议头
		iotpbean.setEnd(iotp.getEnd()); // 协议尾
		iotpbean.setType(iotp.getType()); // 协议类型
		iotpbean.setLicense(iotp.getLicense()); // 节点授权码
		iotpbean.setSequence_id(iotp.getSequence_id()); // 协议序列号
		iotpbean.setDate_time(iotp.getDate_time()); // 创建时间
		iotpbean.setSource_id(iotp.getSource_id()); // 源id
		iotpbean.setSource_type(iotp.getSource_type()); // 源类型
		IOTPBody body = new IOTPBody();
		body.setSubtype(iotp.getBody().getSubtype());
		iotpbean.setBody(body);
		return iotpbean;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: checkIOServerID
	 * @Description: 检测ioserver_id是不是在配置信息中存在
	 * @param @param ioserver_id
	 * @param @return    参数
	 * @return IotsIoserverInfoEntity    返回类型
	 * @throws
	 */
	private IotsIoserverInfoEntity checkIOServerID(String ioserver_id){
		for(IotsIoserverInfoEntity iii:IotsConfig.getInstance().getIpAndPortList()){
			if(ioserver_id.equals(iii.getId())){
				return iii;
			}
		}
		return null;
	}
	
	/**
	 * @author 周西栋
	 * @date 2018年6月20日
	 * @Title: sendCollectionAhentConfig
	 * @Description: 将采集代理的配置信息发送给相应的IOServer
	 * @param @param map
	 * @param @param iotp    参数
	 * @return void    返回类型
	 * @throws
	 */
	private void sendCollectionAhentConfig(Map<IotsIoserverInfoEntity,List<String>> map,IOTPBean iotp){
		// 拿到写线程
		SingleSocketWriteThread write = SingleSocketWriteThread.getInstance();
		for(IotsIoserverInfoEntity iotsIoserverInfoEntity : map.keySet()){
			// 根据iotsIoserverInfoEntity拿到SocketBean
			SocketBean sb = SocketUtils.SOCKETBEAN_MAP.get(iotsIoserverInfoEntity.getIpAddress());// 因为方法type3已经验证过了，所以这里一定会拿到对象
			// 将控制命令发送给IOServer
			IOTPBean iotp_send = getIOTPBeanOfControl(iotp,map.get(iotsIoserverInfoEntity));
			write.send_single(sb, iotp_send);
		}
	}
	
}
